package com.lcy.struct.bTreePlus.disk.core.engine;

import com.lcy.struct.bTreePlus.entity.BplusTreeTransactionInfo;
import com.lcy.struct.bTreePlus.property.BPlusFileInfo;
import com.lcy.struct.bTreePlus.disk.core.BPlusTree;
import com.lcy.struct.bTreePlus.disk.core.BPlusTreeFactory;
import com.lcy.struct.bTreePlus.disk.exception.DuplicateIndexException;
import com.lcy.struct.bTreePlus.disk.item.TreeNode;
import com.lcy.struct.bTreePlus.disk.constants.BPlusPublicConstants;
import lombok.Data;
import lombok.ToString;

import java.util.*;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author lucongyang
 * @date Created in  16:57
 * @description
 */
@ToString
public class BPlusTreeAddEngine {

    private int n;

    private BPlusTree root = null;

    private ReentrantLock needSerializeMapLock = new ReentrantLock();

    private Map<Long, BPlusTree> needSerializeMap = new HashMap<>();

    public static BPlusTreeAddEngine getInstance() {
        return BPlusTreeAddEngineHandler.SINGLETON;
    }

    // 先不考虑数据

    public void addNode(TreeNode treeNode) {
        // 先判断主键是否存在，存在的话拒绝插入
        Object dataOnDisk = BPlusTreeFactory.findLeafOnDisk(treeNode.getIndex());
        if (dataOnDisk != null) {
            throw new DuplicateIndexException("数据" + treeNode.getIndex().getIndexList() + "已存在，不允许重复插入");
        }
        // 如果祖先节点为空，初始化祖先节点
        if (root == null) {
            Long rootPosition = BPlusFileInfo.getRootPosition();
            this.root = rootPosition == null ? new BPlusTree() : BPlusTree.deserialize(rootPosition);
            BPlusFileInfo.setRootPosition(this.root != null ? this.root.getPosition() : null);
        } else {
            Long rootPosition = BPlusFileInfo.getRootPosition();
            this.root = BPlusTreeFactory.getTree(rootPosition);
        }

        // 如果祖先节点是叶子节点
        if (this.root.getChildrenPosition() == null || this.root.getChildrenPosition().size() == 0) {
            int index = treeNode.getIndex().findIndex(this.root.getIndexList());
            this.root.getIndexList().add(index, treeNode.getIndex());
            this.root.addData(index, treeNode.getData());
            // 如果要分裂
            if (this.root.getIndexList().size() >= n) {
                split(this.root);
            } else {
                if (this.root.getPosition() == null) {
                    this.root.setPosition(BPlusFileInfo.allocate(BPlusPublicConstants.PAGE_INFO_SIZE + BPlusPublicConstants.PAGE_SIZE));
                    BPlusFileInfo.setRootPosition(this.root.getPosition());
                }
            }
            addNeedSerialize(this.root);
        }
        // 如果祖先节点不是叶子节点
        else {
            // 先找到在哪个叶子节点上
            BPlusTree leaf = findIdInLeaf(this.root, treeNode);
            int index = treeNode.getIndex().findIndex(leaf.getIndexList());
            leaf.getIndexList().add(index, treeNode.getIndex());
            leaf.addData(index, treeNode.getData());
            // 如果要分裂
            if (leaf.getIndexList().size() >= n) {
                split(leaf);
            }
            addNeedSerialize(leaf);
        }
        BPlusFileInfo.countAddOne();
    }

    /**
     * 只能被消费一次
     *
     * @return 事务中需要持久化数据
     */
    public BplusTreeTransactionInfo getSerializeCacheNeed() {
        // todo 加锁
        BplusTreeTransactionInfo bplusTreeTransactionInfo = new BplusTreeTransactionInfo();
        bplusTreeTransactionInfo.setCount(BPlusFileInfo.getCount());
        bplusTreeTransactionInfo.setEndPosition(BPlusFileInfo.getEndPosition());
        bplusTreeTransactionInfo.setRootPosition(BPlusFileInfo.getRootPosition());

        bplusTreeTransactionInfo.setNeedSerializeMap(this.needSerializeMap);

        this.needSerializeMap = new HashMap<>();
        return bplusTreeTransactionInfo;
    }

    private void split(BPlusTree bPlusTree) {
        if (bPlusTree.getIndexList().size() < n) {
            return;
        }
        List<BPlusTree> splitResult = bPlusTree.splitResult();
        // 左右节点的子节点认父
        if (splitResult.get(0).getChildrenPosition() != null) {
            for (Long childPosition : splitResult.get(0).getChildrenPosition()) {
                BPlusTree child = getNodeOrThrow(childPosition);
                child.setParentPosition(splitResult.get(0).getPosition());
                addNeedSerialize(child);
            }
        }
        if (splitResult.get(2).getChildrenPosition() != null) {
            for (Long childPosition : splitResult.get(2).getChildrenPosition()) {
                BPlusTree child = getNodeOrThrow(childPosition);
                child.setParentPosition(splitResult.get(2).getPosition());
                addNeedSerialize(child);
            }
        }
        // 如果是叶子节点，则关联左右节点
        if (bPlusTree.isLeaf()) {
            splitResult.get(0).setLeftPosition(bPlusTree.getLeftPosition());
            if (bPlusTree.getLeftPosition() != null) {
                BPlusTree bPlusTreeLeft = BPlusTreeFactory.getTree(bPlusTree.getLeftPosition());
                assert bPlusTreeLeft != null;
                bPlusTreeLeft.setRightPosition(splitResult.get(0).getPosition());
                addNeedSerialize(bPlusTreeLeft);
            }
            splitResult.get(0).setRightPosition(splitResult.get(2).getPosition());
            splitResult.get(2).setLeftPosition(splitResult.get(0).getPosition());
            splitResult.get(2).setRightPosition(bPlusTree.getRightPosition());
            if (bPlusTree.getRightPosition() != null) {
                BPlusTree bPlusTreeRight = BPlusTreeFactory.getTree(bPlusTree.getRightPosition());
                assert bPlusTreeRight != null;
                bPlusTreeRight.setLeftPosition(splitResult.get(2).getPosition());
                addNeedSerialize(bPlusTreeRight);
            }
        }
        if (bPlusTree.isRoot()) {
            if (bPlusTree.getPosition() == null) {
                long allocate = BPlusFileInfo.allocate(BPlusPublicConstants.PAGE_INFO_SIZE + BPlusPublicConstants.PAGE_SIZE);
                bPlusTree.setPosition(allocate);
            }
            // 如果是祖先节点
            bPlusTree.setIndexList(splitResult.get(1).getIndexList());
            bPlusTree.setParentPosition(splitResult.get(1).getParentPosition());
            bPlusTree.setChildrenPosition(splitResult.get(1).getChildrenPosition());
            // 去掉数据节点
            bPlusTree.setDataList(null);
            // 认父
            splitResult.get(0).setParentPosition(bPlusTree.getPosition());
            splitResult.get(2).setParentPosition(bPlusTree.getPosition());
            // 纳子
            List<Long> children = new ArrayList<>();
            children.add(splitResult.get(0).getPosition());
            children.add(splitResult.get(2).getPosition());
            bPlusTree.setChildrenPosition(children);

            addNeedSerialize(bPlusTree);
            addNeedSerialize(splitResult.get(0));
            addNeedSerialize(splitResult.get(2));
            return;
        }
        BPlusTree parent = BPlusTreeFactory.getTree(bPlusTree.getParentPosition());
        assert parent != null;
        // 中间的节点加到父节点上
        int index = splitResult.get(1).getIndexList().get(0).findIndex(parent.getIndexList());
        parent.getIndexList().add(index, splitResult.get(1).getIndexList().get(0));
        // 其他两个新节点是父节点的子节点
        splitResult.get(0).setParentPosition(parent.getPosition());
        splitResult.get(2).setParentPosition(parent.getPosition());
        if (parent.getChildrenPosition() != null) {
            int oldIndex = parent.getChildrenPosition().indexOf(bPlusTree.getPosition());
            parent.getChildrenPosition().remove(oldIndex);
            removeSerialize(bPlusTree);
            parent.getChildrenPosition().add(oldIndex, splitResult.get(0).getPosition());
            parent.getChildrenPosition().add(oldIndex + 1, splitResult.get(2).getPosition());
        } else {
            List<Long> children = new ArrayList<>();
            children.add(splitResult.get(0).getPosition());
            children.add(splitResult.get(2).getPosition());
            parent.setChildrenPosition(children);
        }
        addNeedSerialize(splitResult.get(0));
        addNeedSerialize(splitResult.get(2));
        addNeedSerialize(parent);
        if (parent.getIndexList().size() >= n) {
            split(parent);
        }
    }

    private BPlusTree getNodeOrThrow(long position) {
        BPlusTree node = BPlusTreeFactory.getTree(position);
        if (node == null) {
            throw new RuntimeException(position + "节点数据为空");
        }
        return node;
    }

    private void addNeedSerialize(BPlusTree bPlusTree) {
        needSerializeMap.put(bPlusTree.getPosition(), bPlusTree);
        BPlusTreeFactory.addCache(bPlusTree);
    }

    private void removeSerialize(BPlusTree bPlusTree) {
        needSerializeMap.remove(bPlusTree.getPosition());
        BPlusTreeFactory.removeCache(bPlusTree);
    }

    // child position
    private BPlusTree findIdInLeaf(BPlusTree current, TreeNode treeNode) {
        // 先找到在哪个子节点上
        int index = treeNode.getIndex().findIndex(current.getIndexList());
        Long childPosition = current.getChildrenPosition().get(index);
        BPlusTree child = BPlusTreeFactory.getTree(childPosition);
        if (child == null) {
            throw new RuntimeException("子节点不在磁盘上");
        }
        if (child.isLeaf()) {
            return child;
        } else {
            return findIdInLeaf(child, treeNode);
        }
    }

    private BPlusTreeAddEngine(int n) {
        this.n = n;
    }

    private static class BPlusTreeAddEngineHandler {
        private static final BPlusTreeAddEngine SINGLETON = new BPlusTreeAddEngine(BPlusFileInfo.getRankBPlusTree());
    }
}
